/*
 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
 * Licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
#ifndef SE_INTERNAL_SCP_H
#define SE_INTERNAL_SCP_H

#include "tee_defines.h"
#include "tee_internal_se_api.h"
#include "sesrv_api.h"

/* scard_get_status return value defines */
#define SCARD_STATUS_RECEIVE_NOT_READY 0
#define SCARD_STATUS_RECEIVE_READY     1

#define CLA_MASK_B1B2B7              0xBC
#define CLA_MASK_B1B2B3B4B7          0xB0
#define CLA_BASIC_CHANNEL            0x00
#define CLA_MANAGE_CHANNEL           0x00
#define INS_SELECT                   0xA4
#define INS_MANAGE_CHANNEL           0x70
#define P1_SELECT                    0x04
#define P1_MANAGE_CHANNEL_OPEN       0x00
#define P1_MANAGE_CHANNEL_CLOSE      0x80
#define P2_SELECT                    0x00
#define P2_MANAGE_CHANNEL_OPEN       0x00
#define LE_GP_LEN                    1
#define LE_MANAGE_CHANNEL_OPEN       0x01
#define LE_SELECT                    0x00
#define RSP_MANAGE_CHANNEL           0
#define SW1_GP_SUCCESS               0x90
#define SW1_GP_WARNING1              0x62
#define SW1_GP_WARNING2              0x63
#define SW1_GP_REFUSE                0x8F
#define SW1_GP_LEN                   1U
#define SW2_GP_SUCCESS               0x00
#define SW2_GP_REFUSE                0xFF
#define SW2_GP_LEN                   1U
#define SW_GP_LEN                    (SW1_GP_LEN + SW2_GP_LEN)
#define APDU_MANAGE_CHANNEL_RESP_LEN 3U

/* session state: 0-closed, 1-open, -1-invalid */
#define SESSION_STATE_CLOASED 0
#define SESSION_STATE_OPEN    1
#define SESSION_STATE_INVALID (-1)

#define DDA_CONSTANT_INDEX       11
#define DDA_SEPARATION_INDEX     12
#define DDA_DERIVED_DATA_INDEX   13
#define DDA_LEN_INDEX            14
#define DDA_COUNTER_INDEX        15
#define DD_LABEL_LEN             12U
#define DATA_CARD_CRYPTOGRAM     0x00
#define DATA_HOST_CRYPTOGRAM     0x01
#define DATA_DERIVATION_SENC     0x04
#define DATA_DERIVATION_SMAC     0x06
#define DATA_DERIVATION_SRMAC    0x07
#define DATA_DERIVATION_L_64BIT  0x0040
#define DATA_DERIVATION_L_128BIT 0x0080
#define DATA_DERIVATION_KDF_CTR  0x01

/* host/card Challenge byte length */
#define SCP_GP_IU_KEY_DIV_DATA_LEN    10U /* SCP GP Init Update key Div length */
#define SCP_GP_IU_KEY_INFO_LEN        3U  /* SCP GP Init Update key info length */
#define SCP_GP_CARD_CHALLENGE_LEN     8U  /* SCP GP Card Challenge length */
#define SCP_GP_HOST_CHALLENGE_LEN     8U  /* SCP GP Host Challenge length */
#define SCP_GP_IU_CARD_CRYPTOGRAM_LEN 8U  /* SCP GP Card Cryptogram length */
#define SCP_COMMAND_MAC_SIZE          8U  /* length of the MAC appended in the APDU payload (8 'MSB's) */
#define SCP_PADDING_HEAD              0x80
#define SCP_PADDING_CONTENT           0x00
#define SCP_NO_PADDING                0x00
#define SCP_NO_LE                     0

#define CLA_GP_CHANNEL1              0x81
#define CLA_GP_SEC_BASIC_CHANNEL     0x84
#define CLA_GP_SEC_CHANNEL1          0x85
#define INS_GP_INITIALIZE_UPDATE     0x50 /* Global platform defined instruction */
#define INS_GP_EXTERNAL_AUTHENTICATE 0x82 /* Global platform defined instruction */
#define P1_GP_INITIALIZE_UPDATE      0x35
#define P2_GP_INITIALIZE_UPDATE      0x00
#define P2_GP_EXTERNAL_AUTHENTICATE  0x00
#define LC_GP_EXTERNAL_AUTHENTICATE  0x10
#define LE_GP_INITIALIZE_UPDATE      0x00

#define SET_THIRD_BIT   0x4
#define SET_FIR_SEC_BIT 0x03
#define SET_LOW_8BIT    0xFF

/*
 * INITIALIZE UPDATE cmd length
 * '5': CLA-Lc; '8': challenge; '1': Le
 */
#define SCP_INITIALIZE_UPDATE_CMD_LEN 14U
/*
 * INITIALIZE UPDATE Response length
 * '10': Secure Flash Information; '3': Key information
 * '16': 2 challenge; '2': sw;
 */
#define SCP_INITIALIZE_UPDATE_RESP_LEN 31U
#define SCP_KDF_MESSAGE_LEN            32U

/*
 * KDF parameters used in SCP03 calc (if key length is 128bits)
 * [i] || Label || 0x00 || Context || [L]
 * 1      12       1        16        2   bytes
 */
#define SCP_LABLE_LEN         12U
#define SCP_BLOCK_BYTE_LEN    16U
#define SCP_ICV_BYTE_LEN      16U
#define SCP_CMAC_TOTAL_LENGTH 16U
/*
 * EXTERNAL AUTHENTICATE cmd length
 * '5': CLA-Lc; '16': host crypogram and C-MAC;
 */
#define SCP_EXTERNAL_AUTHENTICATE_CMD_LEN 21U
/*
 * EXTERNAL AUTHENTICATE Response length
 * '2': sw;
 */
#define SCP_EXTERNAL_AUTHENTICATE_RESP_LEN 2U

/* length of the CMAC calculated (and used as MAC chaining value) */
#define SCP_CMAC_SIZE         16U
#define SCP_KEY_SIZE          16U
#define SCP_MCV_LEN           16U  /* MAC Chaining Length */
#define MAX_CHUNK_LENGTH_LINK 256U /* Limited by A71CH applet capability */
#define SCP_BUFFER_SIZE       (MAX_CHUNK_LENGTH_LINK + SCP_KDF_MESSAGE_LEN + SW_GP_LEN)
#define ATTRIBUTE_COUNT       1U

#define APDU_LCC_PADDING          (APDU_LC + 1)
#define APDU_LCC_MAC              (APDU_LC + 2)

struct session_state_t {
    uint8_t enc[SCP_KEY_SIZE];     /* SCP03 session channel encryption key */
    uint8_t mac[SCP_KEY_SIZE];     /* SCP03 session command authentication key */
    uint8_t rmac[SCP_KEY_SIZE];    /* SCP03 session response authentication key */
    uint8_t mcv[SCP_MCV_LEN];      /* SCP03 MAC chaining value */
    uint8_t counter[SCP_KEY_SIZE]; /* SCP03 command counter */
};

struct tee_scp03_state_t {
    uint8_t key_enc[SCP_KEY_SIZE];  /* SCP03 static secure channel encryption key */
    uint8_t key_mac[SCP_KEY_SIZE];  /* SCP03 static secure channel authentication key */
    uint8_t key_dek[SCP_KEY_SIZE];  /* SCP03 data encryption key */
    struct session_state_t session; /* SCP03 session state */
};

struct tee_scp03_cipher_params {
    uint8_t *iv;
    uint32_t iv_len;
    uint8_t key[SCP_KEY_SIZE];
    uint32_t algorithm;
    uint32_t operation_mode;
};

struct tee_dda_params {
    uint8_t dda[DATA_DERIVATION_L_128BIT];
    uint16_t dda_len;
    uint8_t constant;
    uint16_t len;
    uint8_t counter;
};

struct scp_gp_challenge {
    uint8_t host_challenge[SCP_GP_HOST_CHALLENGE_LEN];
    uint8_t card_challenge[SCP_GP_CARD_CHALLENGE_LEN];
    uint8_t card_cryptogram[SCP_GP_IU_CARD_CRYPTOGRAM_LEN];
    uint8_t host_cryptogram[SCP_GP_IU_CARD_CRYPTOGRAM_LEN];
};

enum apdu_cmd_offset {
    APDU_CLA = 0,
    APDU_INS,
    APDU_P1,
    APDU_P2,
    APDU_LC,
    APDU_CDATA
};

TEE_Result tee_scp_transmit(struct se_transmit_info_t *transmit_info);
TEE_Result tee_secure_authenticate_channel(TEE_SEChannelHandle se_channel_handle, const TEE_SC_Params *sc_params);
void tee_secure_clean_scp(void);

#endif
